home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2000 / MacHack 2000.toast / pc / The Hacks / Bomb o'Clock / ControlStripSample.c next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  13.3 KB  |  465 lines

  1. /********************************************************************************************
  2.  
  3.     file:        ControlStripSample.c
  4.  
  5.     contains:    a sample Control Strip module
  6.  
  7.     author:        SC        [8/29/93]
  8.     modified:    DTS        06/07/94        rename files, comments to reflect name is
  9.                                         Control Strip (as opposed to Status Bar)
  10.  
  11.     Copyright © 1993 by Apple Computer, Inc.  All rights reserved.
  12.  
  13. ********************************************************************************************/
  14.  
  15. #ifndef  SystemSevenOrLater
  16. #define  SystemSevenOrLater    1
  17. #endif
  18.  
  19. #include <Memory.h>
  20. #include <Menus.h>
  21. #include <Quickdraw.h>
  22. #include <Resources.h>
  23. #include <ToolUtils.h>
  24. #include <Types.h>
  25. #include <Icons.h>
  26. #include "ControlStrip.h"
  27. #include "ControlStripSample.h"
  28.  
  29.  
  30. //////////////////////////////////////////////////////////////////////////////////////////////
  31. //
  32. //    global variables
  33.  
  34. typedef struct Globals {                                // global variables we use while we exist
  35.     Handle            lastIcon;                            //    last icon to be displayed
  36.     Handle            firstIcon;                            //    icon suites displayed in the Control Strip module
  37.     Handle            secondIcon;
  38.     Handle            thirdIcon;
  39.     PicHandle        popupArrowPicture;                    //    picture to show we have a popup menu
  40.     Handle            helpStrings;                        //    balloon help strings for each state
  41.     short            helpStringIndex;                    //    which help string to display
  42.     short            whichIcon;                            //    which icon we're drawing
  43.     MenuHandle        configMenu;                            //    menu to select display options
  44.     short            clockIsUp;                            // 1 = yes, 0 = no
  45.     short             blinkState;                            // 1 = up, 0 = down
  46.     long            ticks;                                // tick count for next draw    
  47.     GDHandle         mainGDH;                            // device I'm supposed to draw upon
  48. } Globals;
  49.  
  50.  
  51. //////////////////////////////////////////////////////////////////////////////////////////////
  52. //
  53. //    information saved across restarts
  54.  
  55. typedef struct SavedSettings {
  56.     OSType            signature;                            //    signature to verify it's for this module
  57.     short            whichIcon;                            //    which icon we're drawing
  58.     short            clockIsUp;                        // 1 = yes, 0 = no
  59. } SavedSettings;
  60.  
  61.  
  62. //////////////////////////////////////////////////////////////////////////////////////////////
  63. //
  64. //    prototypes
  65.  
  66. long Initialize();
  67. void CleanUp(Globals **globs);
  68. void DrawCurrentIcon(Globals *gb, Rect *statusRect);
  69. void GetCurrentIcon(Globals *gb);
  70. long HandleMouseClick(Globals *gb, Rect *statusRect);
  71. short SavePreferences(Globals *gb);
  72. void    DrawClockOnMenuBar(Globals *gb);
  73. GDHandle    FindMonitors(void);
  74.  
  75.  
  76. //////////////////////////////////////////////////////////////////////////////////////////////
  77. //
  78. //    entry point
  79.  
  80. pascal long main(unsigned long message, Globals **globs, Rect *statusRect, GrafPtr statusPort) {
  81. #pragma unused(statusPort)
  82.     char            savedState;
  83.     Globals            *gb;
  84.     long            result;
  85.     Handle            theLastIcon;
  86.     Str255            helpString;
  87.  
  88.  
  89.     if ((long)globs > 0) {                                // if we have globals allocated,
  90.         savedState = HGetState((Handle)globs);            //    save the locked/unlocked state,
  91.         HLock((Handle)globs);                            //    lock the handle to the globals,
  92.         gb = *globs;                                    //    and point to the globals directly
  93.     }
  94.  
  95.     result = 0;                                            // just return zero for unknown messages
  96.     switch(message) {
  97.         case sdevInitModule:                            // initialize the module
  98.             if ((result = Initialize()) > 0) break;        //  and exit if successful
  99.             globs = (Globals **)result;
  100.  
  101.         case sdevCloseModule:                            // clean up before being closed
  102.             CleanUp(globs);
  103.             globs = 0L;
  104.             break;
  105.  
  106.         case sdevFeatures:                                // return feature bits
  107.             result = (1<<sdevWantMouseClicks)    |\
  108.                      (1<<sdevDontAutoTrack)        |\
  109.                      (1<<sdevHasCustomHelp);
  110.             break;
  111.  
  112.         case sdevGetDisplayWidth:                        // return display width
  113.             result = IconWidth +
  114.                         (**gb->popupArrowPicture).picFrame.right - (**gb->popupArrowPicture).picFrame.left;
  115.             break;
  116.  
  117.         case sdevPeriodicTickle:                        // periodic tickle when nothing else is happening
  118.             theLastIcon = gb->lastIcon;                    //    save the last state
  119.             GetCurrentIcon(gb);                            //    update everything
  120.             //if (theLastIcon == gb->lastIcon) break;        //    if everything's the same, just exit
  121.             result += 1<<sdevHelpStateChange;            //    flag a state change in case we're displaying help
  122.  
  123.             statusRect->right = statusRect->left + IconWidth;
  124.             EraseRect(statusRect);                        // erase the icon
  125.  
  126.         case sdevDrawStatus:                            // update the interface in the Control Strip
  127.             DrawCurrentIcon(gb, statusRect);
  128.             DrawClockOnMenuBar(gb);
  129.             break;
  130.  
  131.         case sdevMouseClick:                            // user clicked on the module's display area in the Control Strip
  132.             result = HandleMouseClick(gb, statusRect);
  133.             DrawClockOnMenuBar(gb);
  134.             break;
  135.  
  136.         case sdevSaveSettings:                            // save changed settings
  137.             result = SavePreferences(gb);
  138.             DrawClockOnMenuBar(gb);
  139.             break;
  140.  
  141.         case sdevShowBalloonHelp:                        // display custom balloon help
  142.             SBGetDetachedIndString(helpString, gb->helpStrings, gb->helpStringIndex);
  143.             SBShowHelpString(statusRect, helpString);
  144.             DrawClockOnMenuBar(gb);
  145.             break;
  146.     }
  147.  
  148.     if ((long)globs > 0)                                // if we have globals allocated,
  149.         HSetState((Handle)globs, savedState);            //    restore the locked/unlocked state
  150.  
  151.     return(result);
  152. }
  153. //////////////////////////////////////////////////////////////////////////////////////////////
  154. //
  155. //    draw clock on menubar
  156. void    DrawClockOnMenuBar(Globals *gb)
  157. {
  158.     Str255    timestr;
  159.     unsigned char *twelvestr = "\p12:00 AM";
  160.     unsigned long    secs;
  161.     Rect bounds;
  162.     Rect wideopen;
  163.     Rect erase;
  164.     GrafPtr    oldGrafPtr;
  165.     GrafPtr wmgrprt;
  166.     RgnHandle    oldClip;
  167.     RgnHandle     newClip;
  168.     RgnHandle    grayrgn;
  169.     long    ticks;
  170.     
  171.     GetPort(&oldGrafPtr);
  172.     GetWMgrPort(&wmgrprt);
  173.     wideopen.top = -10000; wideopen.left = -10000; wideopen.right = 10000; wideopen.bottom = 10000;
  174.     
  175.     grayrgn = GetGrayRgn();
  176.     //DebugStr("\pbounds = grayrgn->rgbBBox");
  177.     bounds = (*grayrgn)->rgnBBox;
  178.     bounds.top = 0;
  179.     bounds.left = 0;
  180.     newClip = NewRgn();
  181.     oldClip = NewRgn();
  182.     
  183.     erase.left = bounds.right - 150;
  184.     erase.right = bounds.right - 80;
  185.     erase.top = /*bounds.top*/ 0;
  186.     erase.bottom = 17;
  187.     
  188.     GetDateTime(&secs);
  189.     IUTimeString(secs, 0, timestr);
  190.     
  191.     SetPort(wmgrprt);    
  192.     GetClip(oldClip);
  193.     ClipRect(&wideopen);
  194.     
  195.     if (gb->clockIsUp)
  196.     {
  197.         //Draw current time in 12pt Chicago, distance from right edge
  198.         PenNormal();
  199.         EraseRect(&erase);
  200.         MoveTo(erase.left, erase.bottom - 3);
  201.         DrawString(timestr);
  202.     }
  203.     else
  204.     {
  205.         ticks = TickCount(); //Get tickcount
  206.         
  207.         if (ticks >= gb->ticks)
  208.         {
  209.             gb->ticks += 15;
  210.             gb->blinkState = 1 - gb->blinkState;
  211.             if (gb->blinkState == 0)
  212.             {
  213.                 PenNormal();
  214.                 EraseRect(&erase);
  215.             }
  216.             else
  217.             {
  218.                 //draw 12:00 AM in 12pt Chicago
  219.                 PenNormal();
  220.                 EraseRect(&erase);
  221.                 MoveTo(erase.left, erase.bottom - 3);
  222.                 DrawString(twelvestr);
  223.             }
  224.         }
  225.     }
  226.     SetClip(oldClip);
  227.     SetPort(oldGrafPtr);
  228.     DisposeRgn(oldClip);
  229.     DisposeRgn(newClip);
  230.     
  231. }//DrawClockOnMenuBar
  232.  
  233.  
  234. /*Generate a list of gDevices that are in the system */
  235. GDHandle    FindMonitors(void)
  236. {
  237.     GDHandle    nextDevice = NULL;
  238.     GDHandle Monitors[6];
  239.     long  nMonitors = 0;
  240.     
  241.     nextDevice = GetDeviceList();
  242.     while (nextDevice!= NULL)
  243.     {
  244.         if (TestDeviceAttribute(nextDevice, screenDevice) 
  245.                 && TestDeviceAttribute(nextDevice, screenActive))
  246.         {
  247.             nMonitors = nMonitors+1;
  248.             Monitors[nMonitors-1] = nextDevice;
  249.         }/*it's a screen and its active*/
  250.         nextDevice = GetNextDevice(nextDevice);
  251.     }/*while*/
  252.     return Monitors[0];    //take the primary screen
  253.     //could be smarter and figure out which has the menu bar on it.  tough.
  254. }/*FindMonitors*/
  255.  
  256.  
  257. //////////////////////////////////////////////////////////////////////////////////////////////
  258. //
  259. //    initializes the module
  260.  
  261. long Initialize() {
  262.     short            i;
  263.     long            result;
  264.     Globals            **globs, *gb;
  265.     Str255            prefsResourceName;
  266.     SavedSettings    **preferences;
  267.     Handle            *theIconSuite;
  268.  
  269.     result = -1;                                        // assume failure
  270.  
  271.     if (! (globs = (Globals **)NewHandleClear(sizeof(Globals))))
  272.         return(MemError());                                // allocate the globals
  273.  
  274.     HLock((Handle)globs);                                // lock the globals while using them
  275.     gb = *globs;                                        //  and get a pointer to them
  276.  
  277. //    load and detach the icon suites
  278.  
  279.     theIconSuite = &gb->firstIcon;
  280.     for (i=ThirdIconID-FirstIconID; i>=0; i--) {
  281.         if (result = SBGetDetachIconSuite(theIconSuite, ThirdIconID-i, svAllSmallData))
  282.             goto done;
  283.         theIconSuite++;
  284.     }
  285.  
  286. //    load and detach the ‘up arrow’ picture
  287.  
  288.     if (! (gb->popupArrowPicture = GetPicture(PopupArrowPictID))) goto done;
  289.     DetachResource((Handle)gb->popupArrowPicture);
  290.  
  291. //    load and detach the configuration menu
  292.  
  293.     if (! (gb->configMenu = GetMenu(ConfigMenuID))) goto done;
  294.     DetachResource((Handle)gb->configMenu);
  295.  
  296. //    load and detach the help strings
  297.  
  298.     if (! (gb->helpStrings = Get1Resource('STR#', HelpStringsID))) goto done;
  299.     DetachResource(gb->helpStrings);
  300.  
  301. //    get the module's saved preferences, if any, and configure the module
  302.  
  303.     gb->whichIcon = mShowFirstIcon;
  304.     SBGetDetachedIndString(prefsResourceName, gb->helpStrings, sPrefResourceName);
  305.     if (! SBLoadPreferences(prefsResourceName, (Handle *)&preferences) &&
  306.         ((**preferences).signature == 'CShk'))
  307.         gb->whichIcon = (**preferences).whichIcon;
  308.  
  309.     GetCurrentIcon(gb);                                    // initialize which icon to draw
  310.  
  311.     HUnlock((Handle)globs);                                // unlock the globals
  312.  
  313.     result = (long)globs;                                // return the handle to the globals as the result
  314.  
  315.     gb->ticks = TickCount();
  316.     gb->clockIsUp = 1 - gb->clockIsUp;                    //reverse state of clock
  317.     gb->mainGDH = FindMonitors();
  318.     SavePreferences(gb);
  319.  
  320. done:
  321.     return(result);                                        // return either a handle or an error code
  322. }
  323.  
  324.  
  325. //////////////////////////////////////////////////////////////////////////////////////////////
  326. //
  327. //    disposes of our storage before we get closed
  328.  
  329. void CleanUp(Globals **globs) {
  330.     Globals            *gb;
  331.  
  332.     if ((long)globs <= 0) return;
  333.  
  334.     HLock((Handle)globs);
  335.     gb = *globs;
  336.  
  337.     gb->clockIsUp = 0;    //when we come back up we're cool.
  338.     SavePreferences(gb);
  339.     
  340.     if (gb->firstIcon) DisposeIconSuite(gb->firstIcon, true);
  341.     if (gb->secondIcon) DisposeIconSuite(gb->secondIcon, true);
  342.     if (gb->thirdIcon) DisposeIconSuite(gb->thirdIcon, true);
  343.  
  344.     if (gb->popupArrowPicture) DisposeHandle((Handle)gb->popupArrowPicture);
  345.  
  346.     if (gb->configMenu) DisposeMenu(gb->configMenu);
  347.  
  348.     if (gb->helpStrings) DisposeHandle(gb->helpStrings);
  349.  
  350.     DisposeHandle((Handle)globs);
  351. }
  352.  
  353.  
  354. //////////////////////////////////////////////////////////////////////////////////////////////
  355. //
  356. //    draws the current icon
  357.  
  358. void DrawCurrentIcon(Globals *gb, Rect *statusRect) {
  359.     short            arrowHeight;
  360.  
  361. //    draw the current icon
  362.  
  363.     statusRect->right = statusRect->left + IconWidth;
  364.     (void) PlotIconSuite(statusRect, atNone, ttNone, gb->lastIcon);
  365.  
  366. //    draw an ‘up arrow’ to show that the module has a popup menu
  367.  
  368.     arrowHeight = (**gb->popupArrowPicture).picFrame.bottom - (**gb->popupArrowPicture).picFrame.top;
  369.     statusRect->left = statusRect->right;
  370.     statusRect->right += (**gb->popupArrowPicture).picFrame.right - (**gb->popupArrowPicture).picFrame.left;
  371.     statusRect->top = (statusRect->top + statusRect->bottom - arrowHeight) >> 1;
  372.     statusRect->bottom = statusRect->top + arrowHeight;
  373.     DrawPicture(gb->popupArrowPicture, statusRect);
  374. }
  375.  
  376.  
  377. //////////////////////////////////////////////////////////////////////////////////////////////
  378. //
  379. //    stuffs the icon suite handle of the current icon into gb->lastIcon,
  380. //    and the related help STR# index into gb->helpStringIndex
  381.  
  382. void GetCurrentIcon(Globals *gb) {
  383.  
  384. //    switch (gb->whichIcon) 
  385.     switch (mShowThirdIcon)
  386.     {
  387.         case mShowFirstIcon:
  388.             gb->lastIcon = gb->firstIcon;
  389.             gb->helpStringIndex = sFirstIconHelp;
  390.             break;
  391.  
  392.         case mShowSecondIcon:
  393.             gb->lastIcon = gb->secondIcon;
  394.             gb->helpStringIndex = sSecondIconHelp;
  395.             break;
  396.  
  397.         case mShowThirdIcon:
  398.             gb->lastIcon = gb->thirdIcon;
  399.             gb->helpStringIndex = sThirdIconHelp;
  400.             break;
  401.     }
  402. }
  403.  
  404.  
  405. //////////////////////////////////////////////////////////////////////////////////////////////
  406. //
  407. //    handles a mouse click on the module's display by tracking a popup menu to change settings
  408.  
  409. long HandleMouseClick(Globals *gb, Rect *statusRect) {
  410.     short            menuItem = 3;
  411.     long            result;
  412.  
  413.     gb->clockIsUp = 1 - gb->clockIsUp;
  414.     DrawClockOnMenuBar(gb);
  415.     SavePreferences(gb);
  416.     /*
  417.     SetItemMark(gb->configMenu, gb->whichIcon, sdevMenuItemMark);
  418.                                                     // check the item for the current icon
  419.  
  420.     menuItem = SBTrackPopupMenu(statusRect, gb->configMenu);
  421.                                                     // call the utility routine to display a popup menu
  422.  
  423.     CheckItem(gb->configMenu, gb->whichIcon, false);// uncheck the item for the previous icon
  424.     */
  425.     result = 0;
  426.     if (1)
  427.     {
  428.                                                     // if something was selected,
  429.         //gb->whichIcon = menuItem;                    //    save the menu item number,
  430.         GetCurrentIcon(gb);                            //     update the icon,
  431.         result = 1<<sdevNeedToSave;                    //     and notify the Control Strip that we need to update preferences
  432.     }
  433.  
  434.     return(result);
  435. }
  436.  
  437.  
  438. //////////////////////////////////////////////////////////////////////////////////////////////
  439. //
  440. //    saves the module's settings so they'll be available across restarts
  441.  
  442. short SavePreferences(Globals *gb) {
  443.     short            result;
  444.     SavedSettings    **preferences;
  445.     Str255            prefsResourceName;
  446.  
  447.     preferences = (SavedSettings**)NewHandle(sizeof(SavedSettings));
  448.     if (! (result = MemError())) {                    // allocate a block to hold the settings
  449.  
  450.         (**preferences).signature = 'CShk';            // include a signature to verify it's ours
  451.         (**preferences).whichIcon = gb->whichIcon;    // stuff in the menu item number of the current icon
  452.         (**preferences).clockIsUp = gb->clockIsUp;    // 1 = yes, 0 = no
  453.  
  454.  
  455.         SBGetDetachedIndString(prefsResourceName, gb->helpStrings, sPrefResourceName);
  456.                                                     // get the name of the preferences resource
  457.         result = SBSavePreferences(prefsResourceName, (Handle)preferences);
  458.                                                     // save the settings in the Control Strip's preferences file
  459.  
  460.         DisposeHandle((Handle)preferences);            // get rid of the block
  461.     }
  462.  
  463.     return(result);
  464. }
  465.